objectdef ezvg_Mov
{
  variable uint nextCheckT

  variable bool isMoving
  variable bool isStrafing
  variable bool isTooClose
  variable int destDist
  variable int64 destID
  variable point3f destXYZ
  variable point3f tempXYZ
  variable uint bailoutT
  variable int huntingCurWP
  variable uint departTime
  variable bool wpPulled
  variable bool amHarvesting
  variable int64 tgtLootCorpse
  variable int64 tgtHarvestCorpse
  variable int64 tgtMob
  variable bool toggleRange
  
  ;############################################
  ;##
  ;##  DO NOT FUCK WITH THE FOLLOWING
  ;##
  ;############################################
  
  method Initialize()
  {
    ;This.nextCheckT:Set[0]
    This.huntingCurWP:Set[1]
    This.departTime:Set[0]
    This.wpPulled:Set[FALSE]
    This.amHarvesting:Set[FALSE]
    This.isMoving:Set[FALSE]
    This.isStrafing:Set[FALSE]
    This.isTooClose:Set[FALSE]
    This.toggleRange:Set[FALSE]
  }
  
  method Shutdown()
  {
		VG:ExecBinding[moveforward,release]
		VG:ExecBinding[movebackward,release]
    VG:ExecBinding[strafeleft,release]
    VG:ExecBinding[straferight,release]
  }
  
  method changeNextT(float modT)
  {
    This.nextCheckT:Set[${Math.Calc[${Script.RunningTime}+(${modT}*1000)]}]
  }
  
  member:bool isReady()
  {
    if ${This.nextCheckT} > ${Script.RunningTime}
      return FALSE
    return TRUE
  }
  
  method Reset()
  {
    This.destXYZ:Set[0, 0, 0]
    This.destID:Set[0]
    This.tempXYZ:Set[0, 0, 0]
    This.wpPulled:Set[FALSE]
    This.departTime:Set[0]
    This.toggleRange:Set[FALSE]
    This:Stop
  }
  
  method Stop()
  {
    This.isMoving:Set[FALSE]
    This.isStrafing:Set[FALSE]
    This.isTooClose:Set[FALSE]
		VG:ExecBinding[moveforward,release]
		VG:ExecBinding[movebackward,release]
    VG:ExecBinding[strafeleft,release]
  }
  
  method Start()
  {
    ;if ${This.destID}!=0
      ;echo --- obj_Mov:Start --- ${This.destID}
    ;else
      ;echo --- obj_Mov:Start --- ${This.huntingCurWP} - ${This.destXYZ.X} - ${This.destXYZ.Y}
    VG:ExecBinding[moveforward]
    This.isMoving:Set[TRUE]
    This:changeNextT[0.10]
    This.tempXYZ:Set[${Me.X}, ${Me.Y}, ${Me.Z}]
    This.bailOutT:Set[${Math.Calc[${Script.RunningTime}+5000]}]
  }
  
  method StartStrafe()
  {
    ;echo --- TANK moving to Side ${doPositionSide} or to Front ${doPositionFront} ---
    This.bailOutT:Set[${Math.Calc[${Script.RunningTime}+5000]}]
    This.isStrafing:Set[TRUE]
    This:changeNextT[0.10]
    VG:ExecBinding[strafeleft]
    VG:ExecBinding[moveforward]
  }
  
  member:bool MinDistCheck()
  {
    if !${Me.Target(exists)}
      return TRUE
    if ${This.toggleRange} && ${Me.Target.Distance}<=6
      return FALSE
    if ${minDist}>${Me.Target.Distance}
      return FALSE
    return TRUE
  }
  
  member:bool MaxDistCheck()
  {
    if !${Me.Target(exists)}
      return FALSE
    if ${This.toggleRange} && ${moveToTargetDist}<6 && ${Me.Target.Distance}>5
      return TRUE
    if ${Me.Target.Distance}<=${moveToTargetDist}
      return TRUE
    else
      return FALSE
  }
  
  method TooClose()
  {
    ;echo --- TANK moving backwards ---
    This.bailOutT:Set[${Math.Calc[${Script.RunningTime}+5000]}]
    This.isTooClose:Set[TRUE]
    This:changeNextT[0.10]
    VG:ExecBinding[movebackward]
  }
  
  method MoveToObject(int64 tgtID, int dist)
  {
    This.destID:Set[${tgtID}]
    This.destDist:Set[${dist}]
    This.destXYZ.X:Set[${Pawn[id, ${tgtID}].X}]
    This.destXYZ.Y:Set[${Pawn[id, ${tgtID}].Y}]
    face ${This.destXYZ.X} ${This.destXYZ.Y}
    if ${Pawn[id, ${This.destID}].Distance}>${This.destDist}
      This:Start
  }
  
  method MoveToLoc(float destX, float destY, int precision)
  {
    This.destID:Set[0]
    This.destDist:Set[${precision}]
    This.destXYZ.X:Set[${destX}]
    This.destXYZ.Y:Set[${destY}]
    face ${This.destXYZ.X} ${This.destXYZ.Y}
    This:Start
  }
  
  member:float PosAngle()
  {
    variable float posX
    variable float posY
    variable float disA
    variable float disB
    variable float disC
    variable float posAngle
    if ${Tank.Equal[${Me.FName}]}
    {
      posX:Set[${Pawn[ID, ${PositionID}].X}]
      posY:Set[${Pawn[ID, ${PositionID}].Y}]
    }
    else
    {
      posX:Set[${Pawn[ID, ${TankID}].X}]
      posY:Set[${Pawn[ID, ${TankID}].Y}]
    }
    ; A=Mob, C=Tank, B=ME
    ; disA = Tank to ME
    ; disC = Mob to ME
    ; disB = Mob to Tank
    ; solve for Angle A = arcos ( (disB^2 + disC^2 - disA^2 )/ ( 2 * disB * disC) )
    disA:Set[${Math.Distance[${Me.X}, ${Me.Y}, ${posX}, ${posY}]}] 
    disB:Set[${Math.Distance[${Me.X}, ${Me.Y}, ${Me.Target.X}, ${Me.Target.Y}]}]
    disC:Set[${Math.Distance[${Me.Target.X}, ${Me.Target.Y}, ${posX}, ${posY}]}]
    posAngle:Set[${Math.Calc[( ( ${disC} * ${disC} ) + ( ${disB} * ${disB} ) - ( ${disA} * ${disA} )  ) / ( 2 * ${disB} * ${disC} ) ]}]
    ;echo calculating angle a= ${disA} , b= ${disB} , c= ${disC} , cos= ${posAngle} , acos=${Math.Acos[${posAngle}]}
    return ${Math.Acos[${posAngle}]} 
  }
  
  method selNewWP()
  {
    ;echo --- obj_Mov:selNewWP --- curWP ${This.huntingCurWP}
    This.huntingCurWP:Inc[1]
    if ${This.huntingCurWP}>10
      This.huntingCurWP:Set[1]
    This.wpPulled:Set[FALSE]
    This:changeNextT[0.500]
  }

  member:bool ValidHP()
  {
    if !${Me.Target(exists)} || ${Me.Target.Type.Equal[Resource]}
      return FALSE
    if ( ${Me.TargetHealth}<=${EngagePct} || ${Combat.CommandAssist} ) && ${Me.TargetHealth}>0 && ${Me.Target.IsAttackable} && ( !${Me.Target.IsDead} || ( ${Me.Chunk.DisplayName.Equal[Sands of Sorrow]} && ${Me.TargetHealth}>0 ) )
      return TRUE
    return FALSE
  }

  member:bool OwnerCheckByID(int64 pawnID)
  {
    if !${Pawn[ID, ${pawnID}](exists)}
      return FALSE
    if ${Pawn[ID, ${pawnID}].Owner(exists)}
    {
      if ${Group[${Pawn[ID, ${pawnID}].Owner.Name}](exists)} || ${Pawn[ID, ${pawnID}].OwnedByMe}
        return TRUE
      else
        return FALSE
    }
    return TRUE
  }

  member:bool OwnerCheck()
  {
    if !${Me.Target(exists)}
      return FALSE
    if ${Me.Target.Owner(exists)}
    {
      if ${Group[${Me.Target.Owner.Name}](exists)} || ${Me.Target.OwnedByMe}
        return TRUE
      else
        return FALSE
    }
    return TRUE
  }
  
  member:bool ValidCombatTgt()
  {
    ;echo objMov: ValidCombatTgt check
    if ${This.OwnerCheck} && ${This.ValidHP}
      return TRUE
    return FALSE  
  }
  
  member:bool ValidPullTgt(int64 tgtMob, int dist)
  {
    if ${Pawn[ID, ${tgtMob}].Distance}>${dist} || ${Pawn[ID, ${tgtMob}].CheckCollision(exists)} || !${Pawn[ID, ${tgtMob}].IsAttackable}
      return FALSE
    if  ${Pawn[ID, ${tgtMob}].IsDead}
      return FALSE
    if ${Pawn[ID, ${tgtMob}].Level}<${minLvlPull} || ${Pawn[ID, ${tgtMob}].Level}>${maxLvlPull}
      return FALSE
    if ${This.OwnerCheckByID[${tgtMob}]}
      return TRUE
    else
      return FALSE
  }

  member:bool ValidResourceTgt(int64 resID, int dist)
  {
    if ${resID.Equal[0]} || !${Pawn[ID, ${resID}](exists)}
      return FALSE
    if ${Pawn[ID, ${resID}].Distance} > ${dist}
      return FALSE
    if ${This.OwnerCheckByID[${resID}]} && !${Pawn[ID, ${resID}].Name.Left[6].Equal[remain]} && ${Pawn[ID, ${resID}].IsHarvestable} && !${LavishSettings[HarvestList].FindSetting[${resID}](exists)}
      return TRUE
    return FALSE
  }
  
  member:bool ValidLootTgt()
  {
    if ${This.OwnerCheckByID[${Pawn[Corpse].ID}]} && ${Pawn[Corpse].ContainsLoot} && !${LavishSettings[LootList].FindSetting[${Pawn[Corpse].ID}](exists)}
      return TRUE
    return FALSE
  }
  
  member:bool LootMobClose(int dist)
  {
    if ${Pawn[Corpse].Distance}<=${dist} && ${This.ValidLootTgt}
    {
      This.tgtLootCorpse:Set[${Pawn[Corpse].ID}]
      return TRUE
    }
    return FALSE
  }

  member:bool ResourceClose(int dist)
  {
    if ${This.ValidResourceTgt[${Pawn[Resource].ID}, ${dist}]}
    {
      This.tgtHarvestCorpse:Set[${Pawn[Resource].ID}]
      return TRUE  
    }
    if ${This.ValidResourceTgt[${Pawn[Corpse].ID}, ${dist}]}
    {
      This.tgtHarvestCorpse:Set[${Pawn[Corpse].ID}]
      return TRUE  
    }
    return FALSE
  }

  member:bool AggroNPCClose(int dist)
  {
    variable int64 pullMob
    if ${Pawn[AggroNPC](exists)} && ${doPull}
    {
      if ${This.ValidPullTgt[${Pawn[AggroNPC].ID}, ${dist}]}
        pullMob:Set[${Pawn[AggroNPC].ID}]
    }
    if ${Pawn[NPC](exists)} && ${doPullNPC}
    {
      if ${This.ValidPullTgt[${Pawn[NPC].ID}, ${dist}]}
      {
        if ${pullMob}!=0
        {
          if ${Pawn[ID, ${pullMob}].Distance}>${Pawn[NPC].Distance}
            pullMob:Set[${Pawn[NPC].ID}]
        }
        else
          pullMob:Set[${Pawn[NPC].ID}]
      }
    }
    if ${pullMob}!=0
    {
      This.tgtMob:Set[${pullMob}]
      return TRUE
    }
    else
      return FALSE
  }
  ;############################################
  ;##
  ;##  THIS SHIT YOU CAN DICK AROUND WITH
  ;##
  ;############################################
  
  method LogicPulse()
  {
    ;;echo --- obj_Mov:LogicPulseMove --- ${This.isMoving} vs. ${This.ValidCombatTgt}
    if ${Paused} || ( ${Me.ToPawn.IsDead} && ${Me.Health}==0 )
    {
      if ${This.isMoving} || ${This.isStrafing} || ${This.isTooClose}
        This:Reset
      This:changeNextT[1.00]
      return
    }
    if ${Script.RunningTime}<${This.nextCheckT}
      return
    if ${This.isStrafing}
    {
      face ${Me.Target.X} ${Me.Target.Y}
      if ( ${This.PosAngle}>=125 && ( ${doPositionFront} || ${doPositionBack} ) ) || ( ${This.PosAngle}>=65 && ${This.PosAngle}<=125 && ${doPositionSide} )
        This:Stop
      else
        This:changeNextT[0.10]
    }
    elseif ${This.isTooClose}
    {
      face ${Me.Target.X} ${Me.Target.Y}
      if ${This.MinDistCheck}
        This:Stop
      else
        This:changeNextT[0.10]
    }
    elseif ${This.isMoving}
    {
      ; checking first if we have a valid ID that we're moving to.
      ; if so, are we close enough and should we stop?
      ; what if we have a valid target all ready but it's not our destID?
      if ${This.destID}!=0
      {
        if ${Pawn[id, ${This.destID}].Distance}<=${This.destDist} || ${Pawn[id, ${This.destID}].Distance}>99 ||  !${Pawn[id, ${This.destID}](exists)}
          This:Stop
        elseif ${doPull} && ${Me.Target(exists)}
        {
          if ${Me.Target.ID}!=${This.destID} && ${This.ValidCombatTgt}
          {
            This:Stop
            This.destID:Set[${Me.Target.ID}]
            face ${Me.Target.X} ${Me.Target.Y}
          }
          else
            face ${Pawn[id, ${destID}].X} ${Pawn[id, ${destID}].Y}
        }
        else
        {
          if !${Me.InCombat} && ${Me.Class.Equal[Bard]} && ${doMoveSong} && ${Songs[${moveSong}](exists)} && !${Me.Effect[${Me.FName}'s Bard Song - "${moveSong}"](exists)}
            Songs[${moveSong}]:Perform
          face ${Pawn[id, ${destID}].X} ${Pawn[id, ${destID}].Y}
        }
      }
      elseif ${This.destID.Equal[0]}
      {
        ; This means the HUNT program is running
        if ${Math.Distance[${Me.X},${Me.Y},${This.destXYZ.X},${This.destXYZ.Y}]}<=${This.destDist}
          This:Stop
        else
        {
          if !${Me.InCombat} && ${Me.Class.Equal[Bard]} && ${doMoveSong} && ${Songs[${moveSong}](exists)} && !${Me.Effect[${Me.FName}'s Bard Song - "${moveSong}"](exists)}
            Songs[${moveSong}]:Perform
          if ${This.ValidCombatTgt}
          {
            This:Stop
            This:MoveToObject[${Me.Target.ID}, ${pullDist}]
          }  
          if ( ${doPull} || ${doPullNPC} ) && ${doScanWhileMove} && ${This.AggroNPCClose[${scanWPDist}]}
            This:MoveToObject[${This.tgtMob}, ${pullDist}]
          elseif ${doResources} && ${doScanWhileMove} && ${This.ResourceClose[${scanWPDist}]}
            This:MoveToObject[${This.tgtHarvestCorpse}, 4]
          else
            face ${This.destXYZ.X} ${This.destXYZ.Y}
       }
      }
    }
    elseif ${This.ValidCombatTgt}
    {
      ;;echo --- we have a valid tgt ---
      This:combatLogicMove
    }
    elseif !${Me.InCombat} || !${This.ValidCombatTgt}
    {
      ;;echo --- we're not in combat, doing noncombat move
      This:nonCombatLogicMove
    }
    if ${Script.RunningTime}>${This.nextCheckT}
      This:changeNextT[0.125]
  }
  
  method combatLogicMove()
  {
    ; logic follows this simple priority:
    ; Follow -> Position (if in range) -> Back Out (if inside minDist) -> Move in Range
    ;echo @@@ CombatMov @@@ tgt dist: ${Me.Target.Distance} min dist ${minDist} mov2TgtDist ${moveToTargetDist}
    if ${doCombatFollow} && ${Pawn[ID,${FollowID}].Distance}>${combatFollowDist}
      This:MoveToObject[${FollowID}, ${combatFollowDist}]
    elseif ${This.MinDistCheck} && ${This.MaxDistCheck} && ( ${doPositionFront} || ${doPositionBack} || ${doPositionSide} ) && ${This.ValidCombatTgt}
    {
      ;we're in range, now check position
      ;echo @@@ CombatMov @@@ in range, what's the angle? ${This.PosAngle}
      if ${Tank.Equal[${Me.FName}]} && ${Pawn[ID, ${PositionID}](exists)} && !${Position.Equal[${Me.FName}]} && ( ${doPositionFront} || ${doPositionSide} )
      {
        if ${doPositionFront} && ${Pawn[name, ${Position}].Distance}<16 && ${This.PosAngle}<125
          This:StartStrafe
        elseif ${doPositionSide} && ${Pawn[name, ${Position}].Distance}<16 && ( ${This.PosAngle}<=65 || ${This.PosAngle}>125 )
          This:StartStrafe
      }
      elseif ${Pawn[ID, ${TankID}](exists)} && ( ${doPositionBack} || ${doPositionSide} )
      {
        if ${doPositionBack} && ${This.PosAngle}<=110
          This:StartStrafe
        elseif ${doPositionSide} && ( ${This.PosAngle}<=65 || ${This.PosAngle}>125 )
          This:StartStrafe
      }
    }
    elseif !${This.MinDistCheck} && ( ${Tank.Equal[${Me.FName}]} || !${Me.TargetOfTarget.Name.Equal[${Me.FName}]} )
      This:TooClose
    elseif ${doMoveToTarget} && !${This.MaxDistCheck} && ( !${doCombatFollow} || ( ${doCombatFollow} && ${Math.Distance[${Me.Target.X},${Me.Target.Y},${Pawn[ID, ${FollowID}].X},${Pawn[ID ${FollowID}].Y}]}<=${combatFollowDist} ) )
      This:MoveToObject[${Me.Target.ID}, ${moveToTargetDist}]
  }
  
  method nonCombatLogicMove()
  {
    ;echo objMov:nonCombatLogicMove ---
    if ( ${doLoot} || ${doLootOnly} ) && ${This.LootMobClose[${scanLootRng}]}
        This:MoveToObject[${This.tgtLootCorpse}, 4]  
    elseif ${Me.Target(exists)} && ${Me.Target.IsHarvestable} && ( ${doHarvest} || ${doResources} ) && !${Me.Target.Name.Left[6].Equal[remain]} && !${LavishSettings[HarvestList].FindSetting[${Me.Target.ID}](exists)}
      This:MoveToObject[${Me.Target.ID}, 4]
    elseif !${huntPaused} && !${Me.Encounter}>0
    {
      if ( ${doPull} || ${doPullNPC} ) && ${doPiggyBack} && ${This.AggroNPCClose[${piggyWPDist}]}
          This:MoveToObject[${This.tgtMob}, ${pullDist}]
      elseif ${doResources} && ${doPiggyBack} && ${This.ResourceClose[${piggyWPDist}]}
          This:MoveToObject[${This.tgtHarvestCorpse}, 4]
      elseif ${huntWP[${This.huntingCurWP}].X}!=0 && ${huntWP[${This.huntingCurWP}].Y}!=0
        This:WPMovLogic
      else
      {
        This:selNewWP
        This.departTime:Set[0] 
      }
    }
    elseif ${doFollow} && ${FollowT.NotEqual[${Me.FName}]} && ${Pawn[ID,${FollowID}].Distance}>${FollowDist} && ${Pawn[ID,${FollowID}].Distance}<80
      This:MoveToObject[${FollowID}, ${FollowDist}]
  }
  
  method WPMovLogic()
  {
    if ${Math.Distance[${Me.X},${Me.Y},${huntWP[${This.huntingCurWP}].X},${huntWP[${This.huntingCurWP}].Y}]}<=300
    {
      if ${doPull} && ${This.AggroNPCClose[${huntDist[${This.huntingCurWP}]}]}
      {
        This:MoveToObject[${This.tgtMob}, ${pullDist}]
        This.wpPulled:Set[TRUE]
      }
      elseif ${doResources} && ${This.ResourceClose[${huntDist[${This.huntingCurWP}]}]}  
      {
        This:MoveToObject[${This.tgtHarvestCorpse}, 4]
        This.wpPulled:Set[TRUE]
      }
      else
      {
        if ${huntWPPause[${This.huntingCurWP}]}==999 && !${This.wpPulled}
        {
          This:changeNextT[0.50]
          return
        }
        if ${huntWPPause[${This.huntingCurWP}]}!=999 && ${This.departTime}==0 && ${huntWPPause[${This.huntingCurWP}]}>0
          This.departTime:Set[${Math.Calc[${Script.RunningTime}+(${huntWPPause[${This.huntingCurWP}]}*1000)]}]
        if ${Script.RunningTime}>${This.departTime}
        {
          This:selNewWP
          This.departTime:Set[0]
        }
      }
    }
    elseif ${doPull} || ${doResources}
      This:MoveToLoc[${huntWP[${This.huntingCurWP}].X}, ${huntWP[${This.huntingCurWP}].Y}, 250]
  }
  
  
}

variable ezvg_Mov Mov


